<?php
/**
 * Created by PhpStorm.
 * User: guokunsheng
 * Date: 2021/3/8
 * Time: 下午5:33
 */

namespace app\api\controller\v24;

use app\api\controller\v2\Auth;
use app\common\cachemodel\live\LiveRecordingInfo;
use app\common\cachemodel\RectificationEvent;
use app\common\cachemodel\ZlVisit;
use app\common\lib\exception\ApiException;
use app\common\lib\SensorsData;
use app\common\model\Goods;
use app\common\model\Recode;
use think\Log;

/**
 * 校准生辰
 * @support v2.5.3 神策打点
 * Class Rectification
 * @package app\api\controller\v24
 */
class Rectification extends Auth
{
    protected $visitType = 1;

    /**
     * 校准生辰首页
     */
    public function index()
    {
        $data = [];
        try
        {
            //获取用户最新的矫正记录
            $res = (new \app\common\cachemodel\Rectification())
                ->field('id,start_time,end_time,is_del,status')
                ->where(['uid' => $this->user['id'], 'rid' => $this->user['rid']])
                ->order('id', 'DESC')
                ->find();
            $res = json_decode(json_encode($res), true);
            //若当前矫正记录未删除且未支付
            if (!empty($res) && $res['is_del'] == 0 && $res['status'] == 0)
            {
                //当前记录未生成订单
                $orders = (new \app\common\cachemodel\Orders())->where(['reid' => $res['id']])->find();
                if (!$orders)
                {
                    $event = (new RectificationEvent())->where(['reid' => $res['id']])->field('time,type,desc,id')->order('id', 'ASC')->select();
                    if ($event)
                    {
                        $event = json_decode(json_encode($event, true), true);
                        foreach ($event as $key => $value)
                        {
                            $event[$key]['time'] = $value['time'] ? date('Y-m', $value['time']) : '';
                        }
                        $data['events'] = $event;
                        $data['reid'] = $res['id'];
                        $data['start_time'] = $res['start_time'] ? date('Y-m-d H:i', $res['start_time']) : '';
                        $data['end_time'] = $res['end_time'] ? date('Y-m-d H:i', $res['end_time']) : '';
                    }
                }
            }
            $data['is_first'] = (new ZlVisit())->getVisitData($this->user['id'], $this->visitType);
        }
        catch (\Exception $e)
        {
            Log::write('校准生辰首页：' . $e->getMessage() . '[ ' . $e->getFile() . '：' . $e->getLine() . ' ]', 'error', true);
            $data = [
                'is_first' => 0,
            ];
        }
        return show(config('code.success'), '加载成功', $data);
    }

    /**
     * 更新草稿箱
     */
    public function update()
    {
        // 若is_submit=true 提交校准生辰，需要校验有效事件数量
        $isSubmit = input('is_submit/d', 0);
        $liveId = input('live_id/d', 0);
        $liveRecordId = input('live_record_id/d',0);
        (new LiveRecordingInfo())->checkRecordId($liveId, $liveRecordId);
        $reid = input('reid/d', 0);
        $startTime = trim(input('start_time/s', '', 'htmlspecialchars'));
        $endTime = trim(input('end_time/s', '', 'htmlspecialchars'));
        $time = time();
        if (!$startTime || !$endTime)
        {
            return show(config('code.error'), '请求异常');
        }

        //出生日期和现在的时间
        if (strtotime($startTime) >= $time || strtotime($endTime) >= $time)
        {
            return show(config('code.error'), '出生时间不能大于当前时间');
        }

        //参数校验
        $rec = (new \app\common\cachemodel\Rectification())->getInfoById($reid, ['rid', 'uid', 'status']);
        if (!$rec || $rec['uid'] != $this->user['id'])
        {
            return show(config('code.error'), '数据不存在');
        }

        try
        {
            $startTimestamp = strtotime($startTime);
            $endTimestamp = strtotime($endTime);
            //更新矫正数据
            (new \app\common\cachemodel\Rectification())->saveRec($this->user['id'], $reid, ['start_time' => $startTimestamp, 'end_time' => $endTimestamp, 'update_time' => time()]);
            //检测矫正事件信息
            if ($isSubmit)
            {
                $events = (new RectificationEvent())->batchGetInfoByIds([$reid], ['id', 'time', 'type', 'desc']);
                //提交矫正数据
                $res = $this->checkEvent($reid, $rec['rid'], $startTimestamp, $endTimestamp, $events);
                //检测当前矫正记录是否已生成订单
                if (in_array($rec['status'], [1, 2], false))
                {
                    $res['data']['order_status'] = 1;
                } else
                {
                    $res['data']['order_status'] = 0;
                }
                $eventIdList = [];
                foreach ($events as $v)
                {
                    $eventIdList[] = (string)$v['id'];
                }
                $this->sensorsTrackData('RectificationSubmit', [
                    'uid' => $this->user['id'],
                    'record_id' => (int)$this->user['rid'],
                    'reid' => $reid,
                    'start_time' => date('Y-m-d H:i:s', $startTimestamp),// 出生时间左
                    'end_time' => date('Y-m-d H:i:s', $endTimestamp),// 出生时间右
                    'event_num' => count($eventIdList),// 重大事件数量
                    'event_id_list' => $eventIdList,// 重大事件ID
                    'is_success' => true,// 是否成功
                    'failed_reson' => '',// 失败原因
                    'live_id' => $liveId,
                    'live_record_id' => $liveRecordId,
                ]);
                return show(config('code.success'), $res['msg'], $res['data']);
            }
            return show(config('code.success'), '操作成功');
        }
        catch (\Exception $e)
        {
            Log::write('更新草稿箱失败:' . $e->getMessage() . '【' . $e->getFile() . ':' . $e->getLine() . '】', 'error', true);
            return show(config('code.error'), $e->getMessage());
        }
    }

    /**
     * @title 检测校准生辰事件信息
     * @method POST
     * @desc /rectification
     * @readme /doc/md/rectification/save.md
     * @param $reid
     * @param $rid int
     * @param $start_time int
     * @param $end_time int
     * @param $events array
     * @return array status 0失败，无有效事件，无法继续提交 || 1成功，但是有效事件太少，影响校准生辰结果 || 2成功，等待支付
     * @throws ApiException
     */
    private function checkEvent($reid, $rid, $start_time, $end_time, $events)
    {
        $timeDiff = $end_time - $start_time;

        if ($timeDiff < 0)
        {
            throw new ApiException('开始时间不能大于结束时间', 200, 0);
        } elseif ($timeDiff == 0)
        {
            throw new ApiException('开始时间不能等于结束时间', 200, 0);
        } elseif ($timeDiff > 7200)
        {
            throw new ApiException('校正范围不可超过两小时', 200, 0);
        }

        // 校准生辰事件json
        $nowTime = time();
        // json 转 array
        foreach ($events as $k => $v)
        {
            if ($v['time'] > $nowTime) throw new ApiException('事件时间不能大于当前时间', 200, 0);
        }
        // 用户id
        $uid = $this->user['id'];
        // 检测传参
        if (!$uid || !$rid || !$events || empty($events))
        {
            throw new ApiException('参数错误', 200, 0);
        }
        $recode = (new Recode())->getRecode(['id' => $rid]);

        if (!$recode || $recode['uid'] != $this->user['id'])
        {
            throw new ApiException('档案不存在', 200, 0);
        }
        if (!$recode['isself'])
        {
            throw new ApiException('当前仅限校正自己的档案', 200, 0);
        }
        // 矫正范围的中点时间
        $birth_time_mid = ($start_time + $end_time) / 2;

        // 有效事件判断
        $event_array = (new \app\common\lib\Rectification())->getValidEvents($events, $birth_time_mid, $recode);

        // 初始化有效事件数量
        $vaild_num = 0;
        // 有效事件++
        foreach ($event_array as $ea) if ($ea['status'] == 1) $vaild_num++;

        //判断是否是applePay
        if ($this->is_apple_pay)
        {
            $goods = current($this->apple_goods['rec_goods']);
        } else
        {
            $goods = (new Goods())->getGoodsRec(['id' => 1]);
        }

        if (!$goods || empty($goods))
        {
            throw new ApiException('商品不存在', 200, 0);
        }

        //获取活动折扣
        $activeDiscount = active($goods['id']);
        if ($activeDiscount['discount'] && !$this->is_apple_pay)
        {
            $goods['now_prize'] = sprintf("%.2f", $goods['now_prize'] * $activeDiscount['discount']);
        }

        $ret = [
            'status' => 0,
            'or_amount' => sprintf("%.2f", $goods['or_prize']),
            'total_amount' => sprintf("%.2f", $goods['now_prize']),
            'reid' => $reid
        ];

        if ($vaild_num < 1)
        {
            return [
                'msg' => '无有效事件，会导致校正失败，请继续添加',
                'data' => $ret
            ];
        }

        if ($vaild_num < 3)
        {
            $ret['status'] = 1;
            return [
                'msg' => '有效事件太少，可能导致校正不准确，要继续提交吗',
                'data' => $ret
            ];
        }

        $ret['status'] = 2;
        return [
            'msg' => '待支付',
            'data' => $ret
        ];
    }

    /**
     * 删除草稿
     */
    public function delete()
    {
        $reid = input('reid/d', 0);
        (new \app\common\cachemodel\Rectification())->DelData($this->user['id'], $reid);
        return show(config('code.success'), '操作成功');
    }

    /**
     * 添加事件
     */
    public function addEvent()
    {
        $reid = input('reid/d', 0);// 校准生辰id，可选参数
        $type = input('type/d', 0);// 校准生辰事件类型
        $time = trim(input('time/s', '', 'htmlspecialchars'));// 校准生辰事件时间
        $desc = trim(input('desc/s', '', 'htmlspecialchars'));// 校准生辰事件描述
        $date = trim(input('date/s', '', 'htmlspecialchars'));//出生日期
        $liveId = input('live_id/d', 0);
        $liveRecordId = input('live_record_id/d',0);
        (new LiveRecordingInfo())->checkRecordId($liveId, $liveRecordId);
        $timeStr = strtotime($time);
        $dateStr = strtotime($date);
        $nowDate = date('Y-m-01');

        if (!$type || !$time || !$date)
        {
            return show(config('code.error'), '请求异常');
        }

        //出生日期和现在的时间
        if ($dateStr >= time())
        {
            return show(config('code.error'), '出生时间不能大于当前时间');
        }
        //矫正事件时间不能小于等于出生日期月份。不能大于等于当前日期月份
        if ((strtotime(date('Y-m-1', $timeStr)) <= strtotime(date('Y-m-1', $dateStr))) || (strtotime(date('Y-m-1', $timeStr)) >= strtotime($nowDate)))
        {
            return show(config('code.error'), '事件时间无效');
        }

        // 若校准生辰还未生成，则先生成校准生辰，拿到校准生辰id
        if ($reid <= 0)
        {
            $insertData = [
                'uid' => $this->user['id'],
                'status' => 0,
                'rid' => $this->user['rid'],
                'start_time' => 0,
                'end_time' => 0,
                'create_time' => time(),
            ];
            //生成矫正
            $reid = (new \app\common\cachemodel\Rectification())->saveRec($this->user['id'], 0, $insertData);
        } else
        {
            //参数校验
            $rec = (new \app\common\cachemodel\Rectification())->getInfoById($reid, ['uid']);
            if (!$rec || $rec['uid'] != $this->user['id'])
            {
                return show(config('code.error'), '数据不存在');
            }
        }

        //添加事件
        $data = [
            'type' => $type,
            'time' => strtotime($time),
            'desc' => $desc,
            'reid' => $reid
        ];
        $eId = (new RectificationEvent())->insertGetId($data);
        (new RectificationEvent())->rmEventDetailCache($eId, $reid);

        $this->sensorsTrackData('RectificationEvent', [
            'uid' => $this->user['id'],
            'record_id' => (int)$this->user['rid'],
            'reid' => $reid,
            'event_id' => $eId,
            'event_type' => $type,
            'event_time' => $time,
            'event_note' => $desc,
            'handle_name' => '添加',
            'live_id' => $liveId,
            'live_record_id' => $liveRecordId,
        ]);
        return show(config('code.success'), '操作成功', ['reid' => $reid, 'event_id' => $eId]);
    }

    /**
     * 更新事件
     */
    public function updateEvent()
    {
        $id = input('id/d', 0);// 校准生辰id，可选参数
        $type = input('type/d', 0);// 校准生辰事件类型，
        $time = trim(input('time/s', '', 'htmlspecialchars'));// 校准生辰事件时间
        $desc = trim(input('desc/s', '', 'htmlspecialchars'));// 校准生辰事件描述
        $date = trim(input('date/s', '', 'htmlspecialchars'));//出生日期
        $liveId = input('live_id/d', 0);
        $liveRecordId = input('live_record_id/d',0);
        (new LiveRecordingInfo())->checkRecordId($liveId, $liveRecordId);
        $timeStr = strtotime($time);
        $dateStr = strtotime($date);
        $nowDate = date('Y-m-01');

        if (!$type || !$time || !$date)
        {
            return show(config('code.error'), '请求异常');
        }

        //出生日期和现在的时间
        if ($dateStr >= time())
        {
            return show(config('code.error'), '出生时间不能大于当前时间');
        }

        //矫正事件时间不能小于等于出生日期月份。不能大于等于当前日期月份
        if ((strtotime(date('Y-m-1', $timeStr)) <= strtotime(date('Y-m-1', $dateStr))) || (strtotime(date('Y-m-1', $timeStr)) >= strtotime($nowDate)))
        {
            return show(config('code.error'), '事件时间无效');
        }


        //参数校验
        $event = (new RectificationEvent())->getEventDetail([$id], 'reid');
        if (!$event)
        {
            return show(config('code.error'), '数据不存在');
        }
        $rec = (new \app\common\cachemodel\Rectification())->getInfoById($event[$id]['reid'], ['uid']);
        if (!$rec || $rec['uid'] != $this->user['id'])
        {
            return show(config('code.error'), '数据不存在');
        }
        // 更新事件
        $data = [
            'type' => $type,
            'time' => strtotime($time),
            'desc' => $desc
        ];
        (new RectificationEvent())->where(['id' => $id])->update($data);
        (new RectificationEvent())->rmEventDetailCache($id, $event[$id]['reid']);

        $this->sensorsTrackData('RectificationEvent', [
            'uid' => $this->user['id'],
            'record_id' => (int)$this->user['rid'],
            'event_id' => $id,
            'event_type' => $type,
            'event_time' => $time,
            'event_note' => $desc,
            'handle_name' => '修改',
            'live_id' => $liveId,
            'live_record_id' => $liveRecordId,
        ]);
        return show(config('code.success'), '操作成功');
    }

    /**
     * 删除事件
     */
    public function deleteEvent()
    {
        $id = input('id/d', 0);// 校准生辰id，可选参数
        $liveId = input('live_id/d', 0);
        $liveRecordId = input('live_record_id/d',0);
        (new LiveRecordingInfo())->checkRecordId($liveId, $liveRecordId);
        //参数校验
        $events = (new RectificationEvent())->getEventDetail([$id], 'reid,type,time,desc');
        if (!$events)
        {
            return show(config('code.error'), '数据不存在');
        }
        $rec = (new \app\common\cachemodel\Rectification())->getInfoById($events[$id]['reid'], ['uid']);
        if (!$rec || $rec['uid'] != $this->user['id'])
        {
            return show(config('code.error'), '数据不存在');
        }
        (new RectificationEvent())->where(['id' => $id])->delete();
        (new RectificationEvent())->rmEventDetailCache($id, $events[$id]['reid']);

        $this->sensorsTrackData('RectificationEvent', [
            'uid' => $this->user['id'],
            'record_id' => (int)$this->user['rid'],
            'event_id' => $id,
            'event_type' => $events[$id]['type'],
            'event_time' => date('Y-m', $events[$id]['time']),
            'event_note' => $events[$id]['desc'],
            'handle_name' => '删除',
            'live_id' => $liveId,
            'live_record_id' => $liveRecordId,
        ]);
        return show(config('code.success'), '操作成功');
    }

    /**
     * 校准生辰事件打点
     * @param $event string 事件名称
     * @param $data array 事件数据
     */
    private function sensorsTrackData($event, $data): void
    {
        try
        {
            $recordInfo = (new \app\common\cachemodel\Recode())->getInfoById($data['record_id'], ['id', 'name', 'year', 'month', 'day', 'is_summer']);
            switch ($event)
            {
                case 'RectificationEvent':
                    #神策打点 51 校准生辰重大事件填写 RectificationEvent
                    $sensorsTrackData = [
                        'record_name' => $recordInfo['name'],// 档案名称
                        'record_id' => (int)$recordInfo['id'],// 档案ID
                        'event_type' => $data['event_type'],// 重大事件类型
                        'event_time' => $data['event_time'],// 重大事件发生时间
                        'event_note' => $data['event_note'],// 重大事件关键词
                        'event_id' => $data['event_id'],// 重大事件ID
                        'handle_name' => $data['handle_name'],// 操作类型  添加、修改 、删除
                        'live_id' => $data['live_id'],
                        'live_record_id' => $data['live_record_id'],
                    ];
                    break;
                case 'RectificationSubmit':
                    #神策打点 52 校准生辰提交 RectificationSubmit
                    $sensorsTrackData = [
                        'record_name' => $recordInfo['name'],// 档案名称
                        'record_id' => (int)$recordInfo['id'],// 档案ID
                        'birth_year' => (int)$recordInfo['year'],// 出生年份
                        'birth_month' => (int)$recordInfo['month'],// 出生月份
                        'birth_day' => (int)$recordInfo['day'],// 出生日期
                        'start_time' => $data['start_time'],// 出生时间左
                        'end_time' => $data['end_time'],// 出生时间右
                        'is_summer' => $recordInfo['is_summer'] ? true : false,// 是否为夏令时
                        'event_num' => $data['event_num'],// 重大事件数量
                        'event_id_list' => $data['event_id_list'],// 重大事件ID
                        'is_success' => $data['is_success'],// 是否成功
                        'failed_reson' => $data['failed_reson'],// 失败原因
                        'live_id' => $data['live_id'],
                        'live_record_id' => $data['live_record_id'],
                    ];
                    break;
            }
            if ($event && isset($sensorsTrackData) && !empty($sensorsTrackData))
            {
                SensorsData::track($data['uid'], true, $event, $sensorsTrackData);
            }
        }
        catch (\Exception $e)
        {
            Log::write('神策打点失败：' . $e->getMessage() . '【' . $e->getFile() . ':' . $e->getLine() . '】', 'error', true);
        }
    }
}
